﻿#include "FieldGraphGenerator.h"

#include <vtkTextProperty.h>
#include <vtkActor.h>
#include <vtkPointData.h>
#include <vtkCellData.h>
#include <vtkProperty.h>
#include <vtkScalarBarRepresentation.h>
#include <vtkScalarBarActor.h>
#include <vtkDoubleArray.h>
#include <vtkGlyph3D.h>
#include <vtkLookupTable.h>
#include <vtkPolyDataMapper.h>
#include <vtkDataSetMapper.h>
#include <vtkArrowSource.h>
#include <vtkScalarBarWidget.h>
#include <vtkMaskPoints.h>
#include <vtkLODActor.h>
#include <QDebug>

namespace pst
{

    FieldGraphGenerator::FieldGraphGenerator(QObject* parent)
        : QObject{ parent }
        , m_inputData{ nullptr }
        , m_isScalarAttributeSet{ false }
        , m_isVectorAttributeSet{ false }
        , m_isVectorMaskPointsStrideSet{ false }
        , m_arrow(vtkArrowSource::New())
        , m_geometryActor(vtkActor::New())
        , m_scalarFieldActor(vtkActor::New())
        //    , m_vectorFieldActor(vtkActor::New())
        , m_vectorFieldActor_lod(vtkLODActor::New())
        , m_scalarsScalarBarWidget(vtkScalarBarWidget::New())
        , m_vectorsScalarBarWidget(vtkScalarBarWidget::New())
        , m_scalarsScalarBarActor(vtkScalarBarActor::New())
        , m_vectorsScalarBarActor(vtkScalarBarActor::New())
        , m_geometryMapper(vtkDataSetMapper::New())
        , m_scalarsFieldMapper(vtkDataSetMapper::New())
        , m_vectorsFieldMapper(vtkPolyDataMapper::New())
        , m_vectorsFieldMapper_lowRes(vtkPolyDataMapper::New())
        , m_scalarsFieldLookupTable(vtkLookupTable::New())
        , m_vectorsFieldLookupTable(vtkLookupTable::New())
        , m_arrowGlyph3D(vtkGlyph3D::New())
        , m_maskPointsStride(1)
        , m_maskPts(vtkMaskPoints::New())
        , m_arrowSize(0.6)
        , m_currentUsingScalarType(StructureType::POINTS)
        , m_currentUsingVectorType(StructureType::POINTS)
        , m_currentAddedPointArrayIndex{ -1 }
        , m_currentAddedCellArrayIndex{ -1 }
        , m_currentScalarsArrayRange{ -1,0 }
        , m_currentVectorsArrayRange{ -1,0 }
        , m_maskPts_lowRes(vtkMaskPoints::New())
        , m_arrowGlyph3D_lowRes(vtkGlyph3D::New())
    {
        InitDefaultLookupTable();
        InitScalarsFiledPipeLine();
        InitVectorsFiledPipeLine();
        InitGeometryActor();
    }

    FieldGraphGenerator::~FieldGraphGenerator()
    {
        m_arrow->Delete();
        m_geometryActor->Delete();
        m_scalarFieldActor->Delete();
        //    m_vectorFieldActor->Delete();
        m_scalarsScalarBarActor->Delete();
        m_vectorsScalarBarActor->Delete();

        m_geometryMapper->Delete();
        m_scalarsFieldMapper->Delete();
        m_vectorsFieldMapper->Delete();
        m_vectorsFieldMapper_lowRes->Delete();

        m_scalarsFieldLookupTable->Delete();
        m_vectorsFieldLookupTable->Delete();
        m_arrowGlyph3D->Delete();
        m_arrowGlyph3D_lowRes->Delete();
        m_maskPts->Delete();
        m_maskPts_lowRes->Delete();
        m_vectorFieldActor_lod->Delete();

        m_scalarsScalarBarWidget->Delete();
        m_vectorsScalarBarWidget->Delete();
    }

    void FieldGraphGenerator::SetInputDataSet(vtkDataSet* data)
    {
        m_inputData = data;
        PrintInputDataSetInformation();
    }

    void FieldGraphGenerator::SetScalarsScalarBarWidgetInteractor(vtkRenderWindowInteractor* iren)
    {
        m_scalarsScalarBarWidget->SetInteractor(iren);
    }

    void FieldGraphGenerator::SetVectorsScalarBarWidgetInteractor(vtkRenderWindowInteractor* iren)
    {
        m_vectorsScalarBarWidget->SetInteractor(iren);
    }

    void FieldGraphGenerator::PrintInputDataSetInformation()
    {
        std::cout << std::endl << std::endl << "=============================" << std::endl;
        std::cout << "Input data information:" << std::endl << std::endl;

        std::cout << "points num = " << m_inputData->GetNumberOfPoints() << std::endl;
        std::cout << "Points data array information:" << std::endl << std::endl;
        for (int i = 0; i < m_inputData->GetPointData()->GetNumberOfArrays(); ++i)
        {
            auto array = m_inputData->GetPointData()->GetArray(i);
            PrintArrayInformation(array);
        }

        std::cout << "cell num = " << m_inputData->GetNumberOfCells() << std::endl;
        std::cout << std::endl << "Cells data array information:" << std::endl << std::endl;
        for (int i = 0; i < m_inputData->GetCellData()->GetNumberOfArrays(); ++i)
        {
            auto array = m_inputData->GetCellData()->GetArray(i);
            PrintArrayInformation(array);
        }
        std::cout << "=============================" << std::endl << std::endl << std::endl;
    }

    vtkDataSet* FieldGraphGenerator::GetInputData()
    {
        return m_inputData;
    }

    std::vector<FieldGraphGenerator::ArrayInformation>
        FieldGraphGenerator::GetPointsArrayIndexAndNames()
    {
        std::vector<FieldGraphGenerator::ArrayInformation>  arrayInfoVector;
        FieldGraphGenerator::ArrayInformation tempInfo;

        for (int i = 0; i < m_inputData->GetPointData()->GetNumberOfArrays(); ++i)
        {
            tempInfo.arrayIndex = i;
            tempInfo.arrayName = m_inputData->GetPointData()->GetArrayName(i);
            tempInfo.arrayComponent = m_inputData->GetPointData()->GetArray(i)->GetNumberOfComponents();
            tempInfo.type = StructureType::POINTS;
            arrayInfoVector.push_back(tempInfo);
        }
        return arrayInfoVector;
    }

    std::vector<FieldGraphGenerator::ArrayInformation>
        FieldGraphGenerator::GetCellsArrayIndexAndNames()
    {
        std::vector<FieldGraphGenerator::ArrayInformation>  arrayInfoVector;
        FieldGraphGenerator::ArrayInformation tempInfo;

        for (int i = 0; i < m_inputData->GetCellData()->GetNumberOfArrays(); ++i)
        {
            tempInfo.arrayIndex = i;
            tempInfo.arrayName = m_inputData->GetCellData()->GetArrayName(i);
            tempInfo.arrayComponent = m_inputData->GetCellData()->GetArray(i)->GetNumberOfComponents();
            tempInfo.type = StructureType::CELLS;
            arrayInfoVector.push_back(tempInfo);
        }
        return arrayInfoVector;
    }

    bool FieldGraphGenerator::SetActiveScalarAttribute(int index, const StructureType type, const int compIndex)
    {
        auto polyData = vtkPointSet::SafeDownCast(m_inputData);
        //移除上次额外添加的数组
        polyData->GetPointData()->RemoveArray(m_currentAddedPointArrayIndex);
        polyData->GetCellData()->RemoveArray(m_currentAddedCellArrayIndex);

        switch (type)
        {
        case StructureType::POINTS:
        {
            if (index >= m_inputData->GetPointData()->GetNumberOfArrays() || index < -1)
            {
                std::cout << "Error! Index illegal!" << std::endl;
                return false;
            }

            auto activeScalarArray = m_inputData->GetPointData()->GetArray(index);
            const auto nComponents = activeScalarArray->GetNumberOfComponents();

            //单组分array,忽略组分提取，直接设置
            if (nComponents == 1)
            {
                m_inputData->GetPointData()->SetActiveAttribute(
                    index, vtkDataSetAttributes::AttributeTypes::SCALARS);
                m_scalarsFieldLookupTable->SetTableRange(activeScalarArray->GetRange());
                m_currentScalarsArrayRange[0] = activeScalarArray->GetRange()[0];
                m_currentScalarsArrayRange[1] = activeScalarArray->GetRange()[1];
                //            std::cout<<"Current using points scalar field information:(original) "<<std::endl;
                //            PrintArrayInformation(activeScalarArray);
            }
            else
            {
                if (compIndex < -1 || compIndex >= nComponents)
                {
                    std::cout << "Error! Extracting component index is " << compIndex
                        << ", current array component is " << nComponents << std::endl;
                    return false;
                }

                vtkNew<vtkDoubleArray> magArray;
                bool isSuccess = GetSingleComponent(activeScalarArray, compIndex, magArray);
                if (!isSuccess)
                {
                    std::cout << "Extract component failed!" << std::endl;
                    return false;
                }

                //            std::cout<<"Current using points scalar field information:(Extracted)"<<std::endl;
                //            PrintArrayInformation(magArray);
                m_currentAddedPointArrayIndex = polyData->GetPointData()->AddArray(magArray);
                m_inputData->GetPointData()->SetActiveAttribute(
                    m_currentAddedPointArrayIndex, vtkDataSetAttributes::AttributeTypes::SCALARS);
                m_scalarsFieldLookupTable->SetTableRange(magArray->GetRange());
                m_currentScalarsArrayRange[0] = magArray->GetRange()[0];
                m_currentScalarsArrayRange[1] = magArray->GetRange()[1];
            }
            m_scalarsFieldMapper->SetScalarModeToUsePointData();
            m_currentUsingScalarType = StructureType::POINTS;
            break;
        }

        case StructureType::CELLS:
        {
            if (index >= m_inputData->GetCellData()->GetNumberOfArrays() || index < 0)
            {
                std::cout << "Error! Index illegal!" << std::endl;
                return false;
            }


            auto activeScalarArray = m_inputData->GetCellData()->GetArray(index);
            const auto nComponents = activeScalarArray->GetNumberOfComponents();

            //单组分array,忽略组分提取，直接设置
            if (nComponents == 1)
            {
                m_inputData->GetCellData()->SetActiveAttribute(
                    index, vtkDataSetAttributes::AttributeTypes::SCALARS);
                m_scalarsFieldLookupTable->SetTableRange(activeScalarArray->GetRange());
                m_currentScalarsArrayRange[0] = activeScalarArray->GetRange()[0];
                m_currentScalarsArrayRange[1] = activeScalarArray->GetRange()[1];
                std::cout << "Current using cells scalar field information:(original) " << std::endl;
                PrintArrayInformation(activeScalarArray);
            }
            else
            {
                if (compIndex < -1 || compIndex >= nComponents)
                {
                    std::cout << "Error! Extracting component index is " << compIndex
                        << ", current array component is " << nComponents << std::endl;
                    return false;
                }

                vtkNew<vtkDoubleArray> magArray;
                bool isSuccess = GetSingleComponent(activeScalarArray, compIndex, magArray);
                if (!isSuccess)
                {
                    std::cout << "Extract component failed!" << std::endl;
                    return false;
                }

                m_currentAddedCellArrayIndex = polyData->GetCellData()->AddArray(magArray);
                m_inputData->GetCellData()->SetActiveAttribute(
                    m_currentAddedCellArrayIndex, vtkDataSetAttributes::AttributeTypes::SCALARS);
                m_scalarsFieldLookupTable->SetTableRange(magArray->GetRange());
                m_currentScalarsArrayRange[0] = magArray->GetRange()[0];
                m_currentScalarsArrayRange[1] = magArray->GetRange()[1];
                std::cout << "Current using points scalar field information:(Extracted)" << std::endl;
                PrintArrayInformation(magArray);

            }
            m_scalarsFieldMapper->SetScalarModeToUseCellData();
            m_currentUsingScalarType = StructureType::CELLS;
            break;
        }

        default:
            std::cout << "Wrong structure type" << std::endl;
            return false;
            break;
        }

        m_isScalarAttributeSet = true;
        return true;
    }

    void FieldGraphGenerator::SetScalarsLookupTable(vtkLookupTable* table)
    {
        m_scalarsFieldLookupTable = table;
    }

    vtkLookupTable* FieldGraphGenerator::GetScalarsLookupTable()
    {
        return m_scalarsFieldLookupTable;
    }

    void FieldGraphGenerator::SetScalarBarRange(
        const double minValue, const double maxValue, FieldType type)
    {
        switch (type)
        {
        case FieldType::SCALARS:
        {
            m_scalarsFieldLookupTable->SetTableRange(minValue, maxValue);
            qDebug() << "SetTableRange minValue: " << minValue << " maxValue: " << maxValue;
            break;
        }
        case FieldType::VECTORS:
        {
            m_vectorsFieldLookupTable->SetTableRange(minValue, maxValue);
            break;
        }
        default:
            break;
        }
    }

    bool FieldGraphGenerator::SetScalarBarRangeToAuto(FieldType type)
    {
        switch (type)
        {
        case FieldType::SCALARS:
        {
            if (!m_isScalarAttributeSet)
            {
                std::cout << "Error, scalars attribute must be set !" << std::endl;
                return false;
            }
            m_scalarsFieldLookupTable->SetTableRange(m_currentScalarsArrayRange[0], m_currentScalarsArrayRange[1]);
            break;
        }
        case FieldType::VECTORS:
        {
            if (!m_isVectorAttributeSet)
            {
                std::cout << "Error, vectors attribute must be set !" << std::endl;
                return false;
            }
            m_vectorsFieldLookupTable->SetTableRange(m_currentVectorsArrayRange[0], m_currentVectorsArrayRange[1]);
            break;
        }
        default:
            break;
        }

        return true;
    }

    double* FieldGraphGenerator::GetScalarBarRange(FieldType type)
    {
        switch (type)
        {
        case FieldType::SCALARS:
        {
            return m_scalarsFieldLookupTable->GetRange();
            break;
        }
        case FieldType::VECTORS:
        {
            return m_scalarsFieldLookupTable->GetRange();
            break;
        }
        default:
            break;
        }

        return nullptr;
    }

    void FieldGraphGenerator::SetScalarBarTitle(const QString& newTitle, FieldType type)
    {
        switch (type)
        {
        case FieldType::SCALARS:
        {
            m_scalarsScalarBarActor->SetTitle(newTitle.toStdString().c_str());
            break;
        }
        case FieldType::VECTORS:
        {
            m_vectorsScalarBarActor->SetTitle(newTitle.toStdString().c_str());
            break;
        }
        default:
            break;
        }
    }

    int FieldGraphGenerator::GetScalarBarNumberOfLabels(FieldType type)
    {
        switch (type)
        {
        case FieldType::SCALARS:
        {
            return m_scalarsScalarBarActor->GetNumberOfLabels();
            break;
        }
        case FieldType::VECTORS:
        {
            return m_vectorsScalarBarActor->GetNumberOfLabels();
            break;
        }
        default:
            break;
        }

        return -1;
    }

    QString FieldGraphGenerator::GetScalarBarTitle(FieldType type)
    {
        switch (type)
        {
        case FieldType::SCALARS:
        {
            return m_scalarsScalarBarActor->GetTitle();
            break;
        }
        case FieldType::VECTORS:
        {
            return m_vectorsScalarBarActor->GetTitle();
            break;
        }
        default:
            break;
        }

        return "";
    }

    void FieldGraphGenerator::SetScalarBarNumberOfLabels(const int num, FieldType type)
    {
        switch (type)
        {
        case FieldType::SCALARS:
        {
            m_scalarsScalarBarActor->SetNumberOfLabels(num);
            break;
        }
        case FieldType::VECTORS:
        {
            m_vectorsScalarBarActor->SetNumberOfLabels(num);
            break;
        }
        default:
            break;
        }
    }

    vtkActor* FieldGraphGenerator::GetScalarsFieldActor()
    {
        return m_scalarFieldActor;
    }

    vtkScalarBarActor* FieldGraphGenerator::GetScalarsFieldScalarBarActor()
    {
        return m_scalarsScalarBarActor;
    }

    vtkScalarBarActor* FieldGraphGenerator::GetVectorsFieldScalarBarActor()
    {
        return m_vectorsScalarBarActor;
    }

    bool FieldGraphGenerator::SetActiveVectorsAttribute(int index, const StructureType type)
    {
        constexpr int defaultMaxPoints = 150000;
        switch (type)
        {
        case StructureType::POINTS:
        {
            if (index >= m_inputData->GetPointData()->GetNumberOfArrays() || index < 0)
            {
                std::cout << "Error! Index illegal!" << std::endl;
                return false;
            }

            if (m_inputData->GetPointData()->GetArray(index)->GetNumberOfComponents() != 3)
            {
                std::cout << " To set as a vector attribute, the array must have 3 component!" << std::endl;
                return false;
            }

            m_inputData->GetPointData()->SetActiveAttribute(
                index, vtkDataSetAttributes::AttributeTypes::VECTORS);

            m_vectorsFieldMapper->SetScalarModeToUsePointData();
            auto activeVectorsArray = m_inputData->GetPointData()->GetAttribute(
                vtkDataSetAttributes::AttributeTypes::VECTORS);
            //        std::cout<<"Current using points vectors field information: "<<std::endl;
            //        PrintArrayInformation(activeVectorsArray);
            m_vectorsFieldLookupTable->SetTableRange(activeVectorsArray->GetFiniteRange(-1));
            m_currentVectorsArrayRange[0] = activeVectorsArray->GetFiniteRange(-1)[0];
            m_currentVectorsArrayRange[1] = activeVectorsArray->GetFiniteRange(-1)[1];
            m_currentUsingVectorType = StructureType::POINTS;

            //如果没有手动设置Stride，就设置自动值
            if (!m_isVectorMaskPointsStrideSet)
            {
                auto tupleNum = activeVectorsArray->GetNumberOfTuples();
                m_maskPointsStride = tupleNum / defaultMaxPoints;//可以为0，即不稀疏，(1也不稀疏)
            }

            break;
        }
        case StructureType::CELLS:
        {
            if (index >= m_inputData->GetCellData()->GetNumberOfArrays() || index < 0)
            {
                std::cout << "Error! Index illegal!" << std::endl;
                return false;
            }

            if (m_inputData->GetCellData()->GetArray(index)->GetNumberOfComponents() != 3)
            {
                std::cout << " To set as a vector attribute, the array must have 3 component!" << std::endl;
                return false;
            }

            m_inputData->GetCellData()->SetActiveAttribute(
                index, vtkDataSetAttributes::AttributeTypes::VECTORS);
            m_vectorsFieldMapper->SetScalarModeToUseCellData();
            auto activeVectorsArray = m_inputData->GetCellData()->GetAttribute(
                vtkDataSetAttributes::AttributeTypes::VECTORS);
            //        std::cout<<"Current using cell vectors field information: "<<std::endl;
            //        PrintArrayInformation(activeVectorsArray);
            m_vectorsFieldLookupTable->SetTableRange(activeVectorsArray->GetFiniteRange(-1));
            m_currentVectorsArrayRange[0] = activeVectorsArray->GetFiniteRange(-1)[0];
            m_currentVectorsArrayRange[1] = activeVectorsArray->GetFiniteRange(-1)[1];
            m_currentUsingVectorType = StructureType::CELLS;

            //如果没有手动设置Stride，就设置自动值
            if (!m_isVectorMaskPointsStrideSet)
            {
                auto tupleNum = activeVectorsArray->GetNumberOfTuples();
                m_maskPointsStride = tupleNum / defaultMaxPoints;//可以为0，即不稀疏，(1也不稀疏)
            }

            break;
        }
        default:
        {
            std::cout << "Wrong vector structure type!" << std::endl;
            break;
        }
        }

        m_isVectorAttributeSet = true;
        return true;
    }

    void FieldGraphGenerator::SetMaskPointsStride(const int stride)
    {
        m_maskPointsStride = stride;
        m_isVectorMaskPointsStrideSet = true;
    }

    void FieldGraphGenerator::SetArrowSize(const double size)
    {
        m_arrowSize = size;
        UpdateVectorsFieldActor();
    }

    double FieldGraphGenerator::GetArrowSize()
    {
        return m_arrowGlyph3D->GetScaleFactor();
    }

    vtkGlyph3D* FieldGraphGenerator::GetArrowGlyph()
    {
        return m_arrowGlyph3D;
    }

    void FieldGraphGenerator::SetVectorsLookupTable(vtkLookupTable* table)
    {

        m_vectorsFieldMapper->SetLookupTable(table);
    }

    vtkActor* FieldGraphGenerator::GetVectorsFieldActor()
    {
        //    return m_vectorFieldActor;
        return m_vectorFieldActor_lod;
    }

    void FieldGraphGenerator::SetGeometryActorColor(
        const double r, const double g, const double b)
    {
        m_geometryActor->GetProperty()->SetColor(r, g, b);
    }

    void FieldGraphGenerator::UpdateScalarFieldActor()
    {
        if (m_isScalarAttributeSet)
        {
            m_scalarsFieldMapper->SetInputData(m_inputData);
            m_scalarsFieldMapper->SetLookupTable(m_scalarsFieldLookupTable);
            m_scalarsFieldMapper->SetInterpolateScalarsBeforeMapping(true);
            m_scalarsFieldMapper->SetColorModeToMapScalars();
            m_scalarsFieldMapper->ScalarVisibilityOn();
            m_scalarsFieldMapper->SetUseLookupTableScalarRange(1);
            m_scalarsFieldMapper->Update();
            m_scalarFieldActor->SetMapper(m_scalarsFieldMapper);
            m_scalarFieldActor->GetProperty()->SetRepresentationToSurface();
            //        m_scalarFieldActor->GetProperty()->SetRepresentationToWireframe();

            m_scalarsScalarBarWidget->On();
        }
        else
        {
            std::cout << "A scalar field should be activated first! " << std::endl;
        }
    }

    void FieldGraphGenerator::UpdateVectorsFieldActor()
    {
        if (m_isVectorAttributeSet)
        {
            ReinitVectorFiledSetting();
            m_vectorsScalarBarWidget->On();
        }
        else
        {
            std::cout << "A vector field should be activated first! " << std::endl;
        }
    }

    void FieldGraphGenerator::UpdateGeometryActor()
    {
        m_geometryMapper->SetInputData(m_inputData);
        m_geometryMapper->Update();
    }

    vtkActor* FieldGraphGenerator::GetGeometryActor()
    {
        return m_geometryActor;
    }

    void FieldGraphGenerator::ReinitVectorFiledSetting()
    {
        //必须先在m_inputData中设置了矢量场属性，然后放置到m_arrowGlyph3D才可生效
        //因此重新设置了新的矢量场属性之后，需要重新走输入管线
        //每m_maskPointsStride个采样一个
        m_maskPts->SetOnRatio(m_maskPointsStride);
        m_maskPts->RandomModeOn();
        m_maskPts->SetInputData(m_inputData);
        m_maskPts->Update();
        //    m_maskPts->GetOutput()->Print(std::cout);

        m_arrowGlyph3D->SetInputData(m_maskPts->GetOutput());

        m_arrowGlyph3D->SetScaleFactor(m_arrowSize);
        m_arrowGlyph3D->Update();

        m_vectorsFieldMapper->SetInputData(m_arrowGlyph3D->GetOutput());
        m_vectorsFieldMapper->SetColorModeToMapScalars();
        m_vectorsFieldMapper->SetLookupTable(m_vectorsFieldLookupTable);
        m_vectorsFieldMapper->ScalarVisibilityOn();
        m_vectorsFieldMapper->SetUseLookupTableScalarRange(1);
        m_vectorsFieldMapper->SetInterpolateScalarsBeforeMapping(true);
        m_vectorsFieldMapper->Update();

        //============low resolution========

        m_maskPts_lowRes->SetOnRatio(5 * m_maskPointsStride);
        m_maskPts_lowRes->RandomModeOn();
        m_maskPts_lowRes->SetInputData(m_inputData);
        m_maskPts_lowRes->Update();
        //    m_maskPts_lowRes->GetOutput()->Print(std::cout);

        m_arrowGlyph3D_lowRes->SetInputData(m_maskPts_lowRes->GetOutput());

        m_arrowGlyph3D_lowRes->SetScaleFactor(m_arrowSize);
        m_arrowGlyph3D_lowRes->Update();

        m_vectorsFieldMapper_lowRes->SetInputData(m_arrowGlyph3D_lowRes->GetOutput());
        m_vectorsFieldMapper_lowRes->SetColorModeToMapScalars();
        m_vectorsFieldMapper_lowRes->SetLookupTable(m_vectorsFieldLookupTable);
        m_vectorsFieldMapper_lowRes->ScalarVisibilityOn();
        m_vectorsFieldMapper_lowRes->SetUseLookupTableScalarRange(1);
        m_vectorsFieldMapper_lowRes->SetInterpolateScalarsBeforeMapping(true);
        m_vectorsFieldMapper_lowRes->Update();
    }

    void FieldGraphGenerator::InitGeometryActor()
    {
        m_geometryMapper->ScalarVisibilityOff();
        m_geometryActor->SetMapper(m_geometryMapper);
        m_geometryActor->GetProperty()->SetColor(
            0.972549019, 0.9725490196, 0.64313725490);
    }

    void FieldGraphGenerator::InitScalarsFiledPipeLine()
    {
        m_scalarsScalarBarActor->SetTitle("scalars field");
        m_scalarsScalarBarActor->SetBarRatio(0.25);
        m_scalarsScalarBarActor->GetTitleTextProperty()->SetJustificationToLeft();
        m_scalarsScalarBarActor->SetPosition(0.8, 0.1);
        m_scalarsScalarBarActor->SetPosition2(0.08, 0.7);
        m_scalarsScalarBarActor->SetNumberOfLabels(10);
        m_scalarsScalarBarActor->SetLookupTable(m_scalarsFieldLookupTable);

        m_scalarsScalarBarWidget->SetScalarBarActor(m_scalarsScalarBarActor);
        vtkScalarBarRepresentation* rep =
            vtkScalarBarRepresentation::SafeDownCast(m_scalarsScalarBarWidget->GetRepresentation());
        rep->SetPosition(0.8, 0.1);
        rep->SetPosition2(0.08, 0.7);
    }

    void FieldGraphGenerator::InitVectorsFiledPipeLine()
    {
        m_vectorsScalarBarActor->SetTitle("vectors field");
        m_vectorsScalarBarActor->SetBarRatio(0.25);
        m_vectorsScalarBarActor->GetTitleTextProperty()->SetJustificationToLeft();
        m_vectorsScalarBarActor->SetPosition(0.9, 0.1);
        m_vectorsScalarBarActor->SetPosition2(0.08, 0.7);
        m_vectorsScalarBarActor->SetNumberOfLabels(10);
        m_vectorsScalarBarActor->SetLookupTable(m_vectorsFieldLookupTable);

        m_arrow->Update();
        m_arrowGlyph3D->SetSourceData(m_arrow->GetOutput());
        m_arrowGlyph3D->SetScaleModeToScaleByVector();//使用点上的vector数据控制缩放
        m_arrowGlyph3D->SetColorModeToColorByVector();
        m_arrowGlyph3D->SetVectorModeToUseVector();//使用vector数据进行操作
        m_arrowGlyph3D->SetOrient(true);

        m_arrowGlyph3D_lowRes->SetSourceData(m_arrow->GetOutput());
        m_arrowGlyph3D_lowRes->SetScaleModeToScaleByVector();//使用点上的vector数据控制缩放
        m_arrowGlyph3D_lowRes->SetColorModeToColorByVector();
        m_arrowGlyph3D_lowRes->SetVectorModeToUseVector();//使用vector数据进行操作
        m_arrowGlyph3D_lowRes->SetOrient(true);

        //    m_vectorFieldActor->SetMapper(m_vectorsFieldMapper);
        m_vectorFieldActor_lod->AddLODMapper(m_vectorsFieldMapper);
        m_vectorFieldActor_lod->AddLODMapper(m_vectorsFieldMapper_lowRes);

        m_vectorsScalarBarWidget->SetScalarBarActor(m_vectorsScalarBarActor);
        vtkScalarBarRepresentation* rep =
            vtkScalarBarRepresentation::SafeDownCast(m_vectorsScalarBarWidget->GetRepresentation());
        rep->SetPosition2(0.08, 0.7);
        rep->SetPosition(0.9, 0.1);

    }

    void FieldGraphGenerator::InitDefaultLookupTable()
    {
        //色调范围从蓝色到红色
        m_scalarsFieldLookupTable->SetNumberOfColors(150);
        m_scalarsFieldLookupTable->SetHueRange(0.67, 0.0);
        m_scalarsFieldLookupTable->Build();

        m_vectorsFieldLookupTable->SetNumberOfColors(150);
        m_vectorsFieldLookupTable->SetHueRange(0.67, 0.0);
        m_vectorsFieldLookupTable->Build();
    }

    void FieldGraphGenerator::PrintArrayInformation(vtkDataArray* array)
    {
        std::cout << "name = " << array->GetName() << std::endl
            << "size = " << array->GetNumberOfTuples() << std::endl
            << "component = " << array->GetNumberOfComponents() << std::endl
            << "scalar range = " << array->GetRange()[0]
            << " " << array->GetRange()[1] << std::endl << std::endl;
    }

    bool FieldGraphGenerator::GetSingleComponent(vtkDataArray* array,
        const int componentIndex, vtkDoubleArray* returnArray)
    {
        auto nComponents = array->GetNumberOfComponents();
        std::cout << " nComponents = " << nComponents << std::endl;

        //检查下标合法性，-1代表取magnitude
        if (componentIndex < -1 || componentIndex >= nComponents)
        {
            return false;
        }

        //取单个组分的属性的0组分，即返回自己
        if (componentIndex == 0 && nComponents == 1)
        {
            returnArray->DeepCopy(vtkDoubleArray::SafeDownCast(array));
            return true;
        }

        const auto nTuples = array->GetNumberOfTuples();
        std::cout << " nTuples = " << nTuples << std::endl;

        vtkNew<vtkDoubleArray> singleArray;
        singleArray->SetNumberOfComponents(1);
        singleArray->SetNumberOfTuples(nTuples);

        //取magnitude
        if (componentIndex == -1)
        {
            std::cout << "magnitude " << std::endl;
            singleArray->SetName("Magnitude");
            for (vtkIdType i = 0; i < nTuples; ++i)
            {
                double mag = 0;
                for (int j = 0; j < nComponents; ++j)
                {
                    double tmp = array->GetComponent(i, j);
                    mag += tmp * tmp;
                }
                mag = sqrt(mag);
                singleArray->InsertTuple1(i, mag);
            }
        }
        else //取现有的单个组件
        {
            std::cout << "extract comp =  " << componentIndex << std::endl;

            if (componentIndex == 0)
            {
                singleArray->SetName("X");
            }
            else if (componentIndex == 1)
            {
                singleArray->SetName("Y");
            }
            else if (componentIndex == 2)
            {
                singleArray->SetName("Z");
            }
            else
            {
                singleArray->SetName(std::to_string(componentIndex).c_str());
            }


            for (vtkIdType j = 0; j < nTuples; ++j)
            {
                singleArray->InsertTuple1(j, array->GetComponent(j, componentIndex));
                //if(j<50)
                //{
                //    std::cout<<"bb= "<<array->GetComponent(j,componentIndex)<<std::endl;
                //}
            }
        }
        returnArray->DeepCopy(singleArray);
        return true;
    }

}//namespace pst
